Completed
Push — master ( 301354...df578b )
by Andres
29s
created

angular.controller(ꞌct_redoxꞌ)   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
c 1
b 0
f 1
nc 4
dl 0
loc 23
rs 9.0856
nop 2
1
/**
2
 redox
3
 Component that handles reduction/oxidation and ions.
4
5
 @namespace Components
6
 */
7
'use strict';
8
9
angular.module('game').component('redox', {
10
  templateUrl: 'views/redox.html',
11
  controller: 'ct_redox',
12
  controllerAs: 'ct'
13
});
14
15
angular.module('game').controller('ct_redox', ['state', 'data', 'visibility', 'util', 'format', 'reaction',
16
  function (state, data, visibility, util, format, reaction) {
17
    let ct = this;
18
    ct.state = state;
19
    ct.data = data;
20
    ct.util = util;
21
    ct.format = format;
22
    ct.reaction = reaction;
23
24
    function update(player) {
25
      processRedox(player);
26
      processElectronegativity(player);
27
    }
28
29
    function processRedox(player){
30
      for(let slot of player.element_slots){
31
        if(!slot){
32
          continue;
33
        }
34
        for (let redox of slot.redoxes) {
35
          if (!redox.resource || !redox.active) {
36
            continue;
37
          }
38
39
          let reactant = ct.generateName(redox.element, redox.from);
40
          let power = ct.redoxPower(player);
41
          let number = Math.min(power, player.resources[reactant].number);
42
          let react = ct.redoxReaction(redox);
43
44
          ct.reaction.react(number, react, player);
45
        }
46
      }
47
    }
48
49
    function processElectronegativity(player){
50
      for(let key in data.elements){
51
        let element = data.elements[key];
52
        if(element.electronegativity === 0){
53
          continue;
54
        }
55
        let ions = element.anions.concat(element.cations);
56
		    ions.push(element.main);
57
        for(let resource of ions){
58
          if(player.resources[resource].number === 0){
59
            continue;
60
          }
61
          let charge = data.resources[resource].charge || 0;
62
          let probabilities = probabilityDistribution(key, charge);
63
          for(let probKey in probabilities){
64
            if(probKey === charge){
65
              continue;
66
            }
67
            let production = Math.floor(probabilities[probKey]*player.resources[resource].number);
68
            if(production === 0){
69
              continue;
70
            }
71
            let react = ct.redoxReaction({
72
              element: key,
73
              from: charge,
74
              to: parseInt(probKey, 10)
75
            });
76
            // electronegativity is 'for free'
77
      			react.reactant.eV = 0;
78
      			react.reactant['e-'] = 0;
79
            ct.reaction.react(production, react, player);
80
          }
81
        }
82
      }
83
    }
84
85
    function probabilityDistribution(element, charge){
86
    	let prob = {};
87
    	let start = -data.elements[element].electron_affinity.length;
88
    	let end = charge;
89
    	// lower than index, affected by negativity
90
    	rangeProbability(element, prob, start, end, 1, data.elements[element].negative_factor);
91
92
    	prob[charge] = 1;
93
94
    	start = charge+1;
95
    	end = data.elements[element].ionization_energy.length+1;
96
    	// lower than index, affected by positivity
97
    	rangeProbability(element, prob, start, end, -1, data.elements[element].positive_factor);
98
99
    	let sum = 0;
100
    	for(let i in prob){
101
    		sum += prob[i];
102
    	}
103
    	for(let i in prob){
104
    		prob[i] /= sum;
105
    	}
106
    	return prob;
107
    }
108
109
    function rangeProbability(element, prob, start, end, offset, factor){
110
    	for(let i = start; i < end; i++){
111
    		let difference = data.redox[element][i]-data.redox[element][i+offset];
112
    		if(difference <= 0){
113
    			difference = -difference;
114
    		}else{
115
    			difference = 1/difference;
116
    		}
117
    		prob[i] = data.constants.ELECTRONEGATIVITY_CHANCE*factor*difference;
118
    	}
119
    }
120
121
    /* Calculates the redox power based on the redox upgrades */
122
    ct.redoxPower = function(player) {
123
      let level = player.global_upgrades.redox_bandwidth;
124
      let upgrade = data.global_upgrades.redox_bandwidth;
125
      let basePower = upgrade.power;
126
      let polynomial = upgrade.power_poly;
127
      return basePower * Math.floor(Math.pow(level, polynomial));
128
    };
129
130
    /* Writes a redox in the form of a reaction so that we can use the reaction
131
    service to process it */
132
    ct.redoxReaction = function (redox) {
133
      let reactant = ct.generateName(redox.element, redox.from);
134
      let product = ct.generateName(redox.element, redox.to);
135
      let energy = redoxEnergy(redox.from, redox.to, redox.element);
136
137
      let react = {
138
        'reactant': {},
139
        'product': {}
140
      };
141
142
      react.reactant[reactant] = 1;
143
      react.product[product] = 1;
144
      if (energy > 0) {
145
        react.reactant.eV = energy;
146
      } else if (energy < 0) {
147
        react.product.eV = -energy;
148
      }
149
150
      let electron = redox.from - redox.to;
151
      if (electron > 0) {
152
        react.reactant['e-'] = electron;
153
      } else if (electron < 0) {
154
        react.product['e-'] = -electron;
155
      }
156
157
      return react;
158
    };
159
160
    /* Calculates how much energy it takes to go from a redox level to another
161
    for a given element */
162
    function redoxEnergy(from, to, element) {
163
      let energyFrom = data.redox[element][from];
164
      let energyTo = data.redox[element][to];
165
      let energy = energyTo - energyFrom;
166
167
      return energy;
168
    }
169
170
    /* Generates the name of a ion, e.g. O3+ */
171
    ct.generateName = function (element, i) {
172
      if (i === 0) {
173
        return data.elements[element].main;
174
      }
175
      let postfix = '';
176
      if (Math.abs(i) > 1) {
177
        postfix = Math.abs(i);
178
      }
179
      postfix += getSign(i);
180
      let name = element + postfix;
181
      // special case!! H+ is just a proton
182
      if (name === 'H+') {
183
        name = 'p';
184
      }
185
      return name;
186
    };
187
188
    function getSign(number) {
189
      return number > 0 ? '+' : '-';
190
    }
191
192
    /* Calculates the number of redox slots based on the redox upgrades */
193
    ct.redoxSlots = function (player) {
194
      let level = player.global_upgrades.redox_slots;
195
      let upgrade = data.global_upgrades.redox_slots;
196
      let basePower = upgrade.power;
197
      let multiplier = upgrade.power_mult;
198
      return basePower * Math.floor(multiplier * level);
199
    };
200
201
    ct.redoxSize = function (player) {
202
      let size = 0;
203
      for(let slot of player.element_slots){
204
        if(!slot){
205
          continue;
206
        }
207
        size += slot.redoxes.length;
208
      }
209
      return size;
210
    };
211
212
    /* Adds a new redox to the player list */
213
    ct.addRedox = function (player, slot) {
214
      if(ct.redoxSize(player) >= ct.redoxSlots(player)){
215
        return;
216
      }
217
      slot.redoxes.push({
218
        resource: data.elements[slot.element].main,
219
        active: false,
220
        element: slot.element,
221
        from: 0,
222
        to: 1
223
      });
224
    };
225
226
    ct.removeRedox = function (slot, index) {
227
      slot.redoxes.splice(index, 1);
228
    };
229
230
    ct.visibleRedox = function(slot) {
231
      return slot.redoxes;
232
    };
233
234
    state.registerUpdate('redox', update);
235
  }
236
]);
237